/*LICENSE_BEGIN
 * ******************************************************************
 * Copyright 2006 by the Dainamite Robocup-Team at the
 * DAI-Labor, TU-Berlin (www.dai-labor.de)
 * 
 * Members of Dainamite are:
 * Holger Endert
 * Robert Wetzker
 * Thomas Karbe
 * Axel Heßler
 * Philippe Bütter
 * Felix Brossmann
 * 
 * Licensed under the GNU GPL (General Public License) Free Software 
 * License, Version 2. You may use this file only in compliance with 
 * the License. You may obtain a copy of the License at:
 * 
 * http://www.fsf.org/licensing/licenses/gpl.txt
 * ******************************************************************
LICENSE_END*/
package robocup.component.infotypes;

import java.util.ArrayList;

/**
 * This class represents a collection of all seen objects of a certain cycle
 * for one player. These objects can be flags, lines, players and the ball.
 * For each of these types, a predefined list (buffers) of possible objects (except for 
 * the ball, which is unique) exists, were the corresponding elements can
 * be taken from, and added to the lists of seen items (for saving performance).
 */
public class VisualInfo extends Info {

	/**
	 * A buffer for seeable flags.
	 */
	private ArrayList<FlagInfo> flagBuffer = new ArrayList<FlagInfo>();

	/**
	 * A buffer for seeable lines.
	 */
	private ArrayList<LineInfo> lineBuffer = new ArrayList<LineInfo>();

	/**
	 * A buffer for seeable players.
	 */
	private ArrayList<PlayerInfo> playerBuffer = new ArrayList<PlayerInfo>();

	/**
	 * The ball-buffer
	 */
	private BallInfo ballBuffer = new BallInfo(0, 0.0, 0.0, 0.0, 0.0);

	/**
	 * The flags seen in a certain cycle.
	 */
	private ArrayList<FlagInfo> flags = new ArrayList<FlagInfo>();

	/**
	 * The lines seen in a certain cycle.
	 */
	private ArrayList<LineInfo> lines = new ArrayList<LineInfo>();

	/**
	 * The players seen in a certain cycle.
	 */
	private ArrayList<PlayerInfo> players = new ArrayList<PlayerInfo>();

	/**
	 * The seen ball (null, if not seen).
	 */
	private BallInfo ball = null;

	/**
	 * A collection of all visual things perceived in one cycle.
	 * Buffers are initialized (50 flags, 4 lines, 21 players and
	 * 1 ball). <br><br>
	 * 
	 * @param cycle -
	 *            the time, when the objects where seen
	 */
	public VisualInfo(int cycle) {

		super(cycle);
		// fill the buffer
		for (int i = 0; i < 50; i++)
			this.flagBuffer.add(new FlagInfo(0, 0, 0, 0));
		for (int i = 0; i < 4; i++)
			this.lineBuffer.add(new LineInfo(0, 0, 0, 0));
		for (int i = 0; i < 21; i++)
			this.playerBuffer.add(new PlayerInfo(0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
					false, false));
		this.ball = null;

		this.infoType = TYPE_VISUAL;
	}

	/**
	 * This method adds all seen elements back to the buffer 
	 * lists and removes them from seen lists
	 */
	public void reset() {

		for (int i = 0; i < this.lines.size();)
			this.lineBuffer.add(this.lines.remove(0));

		for (int i = 0; i < this.flags.size();)
			this.flagBuffer.add(this.flags.remove(0));

		for (int i = 0; i < this.players.size();)
			this.playerBuffer.add(this.players.remove(0));

		this.ball = null;
	}

	/**
	 * Method that takes a Flag from Buffer and adds it with setted parameters
	 * to the perceived flags.
	 * 
	 * @param cycle -
	 *            the cycle, when the flag was seen
	 * @param id -
	 *            the flags id
	 * @param dDist -
	 *            the diatsnce to the flag
	 * @param dDir -
	 *            the direction to the flag
	 */
	public void addFlag(int cycle, int id, double dDist, double dDir) {

		FlagInfo flag;
		if (this.flagBuffer.size() != 0) {
			flag = this.flagBuffer.remove(0);
			flag.setCycle(cycle);
			flag.setId(id);
			flag.setDistance(dDist);
			flag.setDirection(dDir);
		} else {
			flag = new FlagInfo(cycle, id, dDist, dDir);
		}
		this.flags.add(flag);
	}

	/**
	 * This method takes a line from buffer, sets all values and adds it to the
	 * list of seen lines.
	 * 
	 * @param cycle - the cycle, when the line was seen
	 * @param id - the id of the line
	 * @param dDist - the distance to the line
	 * @param dDir - the direction to the line
	 */
	public void addLine(int cycle, int id, double dDist, double dDir) {

		LineInfo line = this.lineBuffer.remove(0);
		line.setCycle(cycle);
		line.setId(id);
		line.setDistance(dDist);
		line.setDirection(dDir);
		this.lines.add(line);
	}

	/**
	 * This method takes al player from the buffer, sets all given parameters
	 * and adds it to the list of seen players
	 * 
	 * @param cycle -
	 *            the cycle, in which the player was seen
	 * @param type -
	 *            either enemy, friend or unknown
	 * @param iNum -
	 *            the tricot number
	 * @param dDist -
	 *            distance
	 * @param dDir -
	 *            direction
	 * @param dDistChange -
	 *            change-Distance
	 * @param dDirChange -
	 *            change Direction
	 * @param dBodyFacingDir -
	 *            Body Direction
	 * @param dHeadFacingDir -
	 *            Head Direction
	 * @param dPointDir -
	 *            pointing to
	 * @param tackle -
	 *            is tackling
	 * @param goalie -
	 *            is goalie
	 */
	public void addPlayer(int cycle, int type, int iNum, double dDist,
			double dDir, double dDistChange, double dDirChange,
			double dBodyFacingDir, double dHeadFacingDir, double dPointDir,
			boolean tackle, boolean goalie, String teamName) {

		PlayerInfo player = this.playerBuffer.remove(0);
		player.setCycle(cycle);
		player.setType(type);
		player.setId(iNum);
		player.setDistance(dDist);
		player.setDirection(dDir);
		player.setDistChange(dDistChange);
		player.setDirChange(dDirChange);
		player.setBodyDir(dBodyFacingDir);
		player.setHeadDir(dHeadFacingDir);
		player.setPointDir(dPointDir);
		player.setTackle(tackle);
		player.setGoalie(goalie);
		player.setTeamName(teamName);

		this.players.add(player);
	}


	/**
	 * This method sets the ball as seen and updates the 
	 * corresponding values.
	 * @param cycle - when the ball was seen
	 * @param dDist - the distance to the ball
	 * @param dDir - the direction to the ball
	 * @param dDistChange - change in distance of the ball (speed indicator)
	 * @param dDirChange - change in direction of the ball (speed indicator)
	 */
	public void setBall(int cycle, double dDist, double dDir,
			double dDistChange, double dDirChange) {

		if (this.cycle == 0)
			this.cycle = cycle;
		this.ballBuffer.setCycle(cycle);
		this.ballBuffer.setDistance(dDist);
		this.ballBuffer.setDirection(dDir);
		this.ballBuffer.setDistChange(dDistChange);
		this.ballBuffer.setDirChange(dDirChange);

		this.ball = this.ballBuffer;
	}

	/**
	 * @return Returns all seen flags of a certain cycle.
	 */
	public FlagInfo[] getFlags() {

		return (this.flags.toArray(new FlagInfo[this.flags.size()]));
	}

	/**
	 * @return Returns all seen lines of a certain cycle.
	 */
	public LineInfo[] getLines() {
		return (this.lines.toArray(new LineInfo[this.lines.size()]));
	}

	/**
	 * @return Returns all seen players of a certain cycle.
	 */
	public PlayerInfo[] getPlayers() {

		// return (PlayerInfo[])players.toArray();
		return (this.players.toArray(new PlayerInfo[this.players.size()]));
	}

	/**
	 * Returns the ball. This is <code>null</code>, if not seen in the
	 * given cycle.
	 * @return - the ball.
	 */
	public BallInfo getBall() {

		return this.ball;
	}

	/**
	 * Checks, whether nothing was seen. This is the case,
	 * if the corresponding lists for flags, lines and players are
	 * empty, and the ball-reference is null.
	 * @return - true, if no object was seen.
	 */
	public boolean isEmpty() {

		return (this.flags.size() + this.lines.size() + this.players.size() == 0 && this.ball == null);
	}

}
